<?php
/*
 *  This file is part of Urd.
 *
 *  Urd is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 3 of the License, or
 *  (at your option) any later version.
 *  Urd is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program. See the file "COPYING". If it does not
 *  exist, see <http://www.gnu.org/licenses/>.
 *
 * $LastChangedDate: 2008-12-29 23:34:32 +0100 (Mon, 29 Dec 2008) $
 * $Rev: 386 $
 * $Author: gavinspearhead $
 * $Id: urdd_functions.php 386 2008-12-29 22:34:32Z gavinspearhead $
 */

if (!defined('ORIGINAL_PAGE')) die('This file cannot be accessed directly.');


$pathuf = realpath(dirname(__FILE__));


require_once "$pathuf/../functions/defines.php";
require_once "$pathuf/../functions/urdversion.php";
require_once "$pathuf/../functions/autoincludes.php";


function get_base($fn, $ext)
{
        static $extensions = array (
            PAR_EXT => array('vol[0-9]+\+[0-9]+\.par2'),
            ZIP_EXT => array('zip'),
            ARJ_EXT => array('arj', 'a[0-9][0-9]'),
            ACE_EXT => array('ace', 'c[0-9][0-9]'),
            ZR7_EXT => array('7z', '7z\.[0-9][0-9][0-9]'),
            RAR_EXT => array('part[0-9]+\.rar', 'part[0-9]+\.r[0-9][0-9]', '\.r[0-9][0-9]', '\d{3}'),
            SFV_EXT => array('sfv', 'sfvmd5', 'csv', 'csv2', 'csv4', 'sha1', 'md5', 'bsdmd5', 'crc'),
            CAT_EXT => array("(?<!\.7z\.)\d{3}"),
            UUE_EXT => array('[0-9]+\.urd_uuencoded_part')
        );
        if (isset ($extensions[$ext])) {
            foreach (($extensions[$ext]) as $expr) {
                if (preg_match("/^(.*)\.$expr$/i", $fn, $fs))
                    return $fs[1];
            }
            return substr ($fn, 0, strlen($fn) - (1 + strlen($ext))); // remove the $ext if no other match is found
        } else
                return FALSE;
}


function split_filename($filename)
{
    $pos = strrpos($filename, '.');
    if ($pos === FALSE)  // dot is not found in the filename
        return array($filename, ''); // no extension
    else {
        $basename = substr($filename, 0, $pos);
        $extension = substr($filename, $pos+1);
        return array($basename, $extension);
    }
} 


function get_par_rar_files(DatabaseConnection $db, $directory, &$all_files) 
{
    static $extensions = array (
        PAR_EXT => array('par2'),
        ZIP_EXT => array('zip'),
        ARJ_EXT => array('arj', 'a[0-9][0-9]'),
        ACE_EXT => array('ace', 'c[0-9][0-9]'),
        ZR7_EXT => array('7z', '7z\.[0-9][0-9][0-9]'),
        RAR_EXT => array('rar', 'r[0-9][0-9]'),
        SFV_EXT => array('sfv'),
        CAT_EXT => array("(?<!\.7z\.)\d{3}"),
        UUE_EXT => array('urd_uuencoded_part')
    );

    $files = new pr_list($directory);
    if (!is_dir($directory))
        return $files;
    $d = dir($directory);
    $all_files = array();
    while (FALSE !== ($entry = $d->read())) {
        if (in_array($entry, array('.', '..', URDD_DOWNLOAD_LOCKFILE)))
            continue;
        $all_files[] = $entry;
        $mt = match_mime_type($db, $directory . $entry); // find a mime type for the file
        if ($mt !== NULL && isset($extensions[$mt])) {
            $base = get_base($entry, $mt); // try and find the base of the filename, which we use to match all the files against, to collect a set
            if ($base === FALSE)
                list($name, $extension) = split_filename($entry, $extensions[$mt]); //otherwise take just the extension off and use that
            else 
                $name = $base;
            $files->add($mt, $name, $entry);
        } else { // ok no mimetype determent, try by file extension
            foreach($extensions as $ext => $expressions) {
                foreach($expressions as $expr) {
                    if (preg_match("/^.*\.$expr$/i", $entry) ) {
                        $base = get_base($entry, $ext);
                        $files->add($ext, $base, $entry);
                        break;
                    }
                }
            }
        }
    }
    $d->close();
    return $files;
}


function match_mime_type(DatabaseConnection $db, $file)
{ // note: /x-* may not always be defined
    static $mime_types = array (
        PAR_EXT => 'application/x-par2',
        ZIP_EXT => 'application/zip',
        ARJ_EXT => 'application/x-arj',
        ACE_EXT => 'application/x-ace',
        ZR7_EXT => 'application/x-7z-compressed',
        RAR_EXT => 'application/x-rar',
        SFV_EXT => NULL,
        CAT_EXT => NULL,
        UUE_EXT => NULL
    );
    $mt = real_mime_content_type($db, $file, TRUE); // will use the file command... if available
    foreach($mime_types as $ext => $type) {
        if ($mt == $type && $type !== NULL)
            return $ext;
    }
    return NULL;
}


function cleanup_dir($directory, array $files)
{ // remove files left by par2
    assert($directory != '');
    foreach ($files as $f) {
        $fn = $directory . '/' . $f . '.1';
        if (file_exists ($fn))
            unlink($fn);
    }
}


function connect_nntp(DatabaseConnection $db, $id = FALSE)
{ // TODO fix
    echo_debug_function(DEBUG_MAIN, __FUNCTION__);
    if ($id === FALSE) { // should not happen
        write_log('No ServerID given 1 ... dying', LOG_ERR);
        throw new exception ('No Server ID given', ERR_NO_ACTIVE_SERVER);
    }
    else if ($id == 0) { // should not happen
        write_log('No ServerID given 2 ... dying', LOG_ERR);
        throw new exception ('No Server ID given', ERR_NO_ACTIVE_SERVER);
    } else {
        assert(is_numeric($id));
        $usenet_server = $id;
    }
    $usenet_config = get_usenet_server($db, $usenet_server, FALSE);
    $timeout = get_config($db, 'socket_timeout');
    if ($timeout <= 0) {
        write_log('Invalid socket timeout set', LOG_WARNING);
        $timeout = DEFAULT_SOCKET_TIMEOUT;
    }
    $nzb = new URD_NNTP($db, $usenet_config['hostname'], $usenet_config['connection'], $usenet_config['port'], $timeout); 
    $nzb->connect($usenet_config['authentication'], $usenet_config['username'], $usenet_config['password']);
    return $nzb;
}


function set_dirpermissions ($dir, $np, $ndp)
{
    assert($dir != '');
    $files = glob ($dir . '/*', GLOB_NOSORT);
    foreach ($files as $f) {
        if (is_dir($f)) {
            chmod ($f, $ndp);
            set_dirpermissions($f, $np, $ndp);
        } else 
            chmod ($f, $np);
    }
}


function set_permissions(DatabaseConnection $db, $dir)
{ 
    assert($dir != '');
    echo_debug_function(DEBUG_SERVER, __FUNCTION__);
    try {
        $perm = get_config($db, 'permissions');
    } catch (exception $e) {
        write_log('Cannot set permission; db value not set', LOG_NOTICE);
        return;
    }
    if ($perm == '')
        return;

    if (strlen($perm) == 4) {
        $u = $perm[1];
        $g = $perm[2];
        $w = $perm[3];
        $np = octdec($perm) & 0777;
        $ndp = $np; // directory permissions they always get x permissions if they have at least a non 0 value
        if ($g > 0)
            $ndp |= 0010;
        if ($w > 0)
            $ndp |= 0001;
        if ($u > 0)
            $ndp |= 0100;
        if (is_dir($dir)) {
            set_dirpermissions($dir, $np, $ndp);
            chmod($dir, $ndp);
        } else 
            chmod($dir, $np);

    } else {
        write_log('Cannot set permission; incorrect value "' .$perm. '"' , LOG_NOTICE);
        return;
    }
}


function move_file_to_nzb(DatabaseConnection $db, $dlid, $filename, $dlpath, $basename, $ext, $username)
{
    assert($filename != '' && $username != '');
       $from = $filename;
    $fn = basename($filename);
    $dlpath = get_dlpath($db);
    $user_dlpath = $dlpath . NZB_PATH . $username . '/';
        if (substr($user_dlpath, -1, 1) != '/')
        $user_dlpath .= '/';

    if (!is_dir($user_dlpath)) { // if the user specific dir does not exist, create it
        $rv = mkdir($user_dlpath, 0775, TRUE);
        if($rv === FALSE) {
            write_log("Could not create directory $user_dlpath", LOG_ERR);
            return;
        }
    }
    if (!is_writeable($user_dlpath)) {
        $rv = @chmod($user_dlpath, 0775); // sometimes mkdir doesn't set the perms correctly (due to umask??), make sure it is set correctly now
        if($rv === FALSE) {
            write_log("Can't chmod directory: $user_dlpath", LOG_ERR);
            return;
        }
    }
  
    $to = find_unique_name($user_dlpath, '', $basename, $ext, TRUE);
    $rv = rename($from, $to);
    if ($rv === FALSE) 
        write_log('Could not move directory', LOG_ERR);
    else 
        set_download_destination($db, $dlid, $to);
    return $to;
}


function move_download_to_done(DatabaseConnection $db, action $item, $dlid, $username, $type = 'DOWNLOAD')
{
    assert(is_numeric($dlid) && $username != '');
    $from = get_download_destination($db, $dlid);
    $dlname = get_download_name($db, $dlid);
    $dlname = sanitise_download_name($db, $dlname);
    $groupid = get_groupid_dlinfo($db, $dlid);
    try {
        $groupname = group_name($db, $groupid); 
    } catch (exception $e) {
        $groupname = '';
    }
    $preview = $item->get_preview();
    $extended_paths = !$preview;
    $done_part = ($preview === TRUE) ? PREVIEW_PATH : DONE_PATH;
    $dlpath = get_dlpath($db);
    $user_dlpath = $dlpath . $done_part . $username . '/';
    if ($extended_paths) {
        $format_string = get_pref($db, 'format_dl_dir', $username, '');
        $values['u'] = $username;
        $values['g'] = $groupname;
        $values['G'] = $groupid;
        $values['D'] = date('Y-m-d', time()); // date
        $values['y'] = date('y', time()); // year 2 digits
        $values['Y'] = date('Y', time()); // year 4 digits
        $values['m'] = date('m', time()); // month numeric
        $values['d'] = date('d', time()); // day of month
        $values['M'] = date('M', time()); // month short name
        $values['F'] = date('F', time()); // month long name
        $values['w'] = date('w', time()); // day of the week
        $values['W'] = date('W', time()); // week number
        $values['z'] = date('z', time()); // day of the year

        $str = format_setname($format_string, 'dugyYmdMwWz', $values);
        $str = str_replace('../', '', $str); // remove nasty subdirs
        $str = preg_replace('/[^a-zA-Z0-9-()._\/+ ]/', '', $str); // remove "weird" characters
        $user_dlpath .= $str;
    }
    if (substr($user_dlpath, -1, 1) != '/')
        $user_dlpath .= '/';

    if (!is_dir($user_dlpath)) { // if the user specific dir does not exist, create it
        $rv = mkdir($user_dlpath, 0775, TRUE);
        if($rv === FALSE) {
            write_log("Could not create directory $user_dlpath", LOG_ERR);
            return;
        }
    }
    if (!is_writeable($user_dlpath)) {
        $rv = @chmod($user_dlpath, 0775); // sometimes mkdir doesn't set the perms correctly (due to umask??), make sure it is set correctly now
        if($rv === FALSE) {
            write_log("Can't chmod directory: $user_dlpath", LOG_ERR);
            return;
        }
    }
    $to = find_unique_name($user_dlpath, '', $dlname);
    $rv = rename($from, $to);
    if ($rv === FALSE) 
        write_log('Could not move directory', LOG_ERR);
    else 
        set_download_destination($db, $dlid, $to);
}


function get_password(DatabaseConnection $db, $dlid)
{
    echo_debug_function(DEBUG_SERVER, __FUNCTION__);
    assert(is_numeric($dlid));
    $db->escape($dlid, TRUE);
    $sql = "\"password\" FROM downloadinfo WHERE \"ID\" = $dlid";
    $res = $db->select_query($sql,1);
    if ($res === FALSE) 
        return '';
    if (isset($res[0]['password']))
        return $res[0]['password'];
    else 
        return '';
}


function get_timeout(action $item)
{ // in minuts;
    $cnt = $item->get_counter();
    if ($cnt < 100)
        return 1;
    else if ($cnt > 100)
        return 2;
    else if ($cnt > 500)
        return 3;
    else if ($cnt > 1000)
        return 5;
    else if ($cnt > 2500)
        return 10;
    else if ($cnt > 5000)
        return 30;
}


function reschedule_locked_item(DatabaseConnection $db, server_data &$servers, action $item)
{
    try {
        echo_debug('Dl still locked, pausing', DEBUG_SERVER);
        $id = $item->get_id();
        $command = $item->get_command();
        $args = $item->get_args();
        //        $rv = $servers->pause($db, $id, TRUE, 'root');
        $item->pause($db, TRUE, 'root');
        //var_dump($rv, $item);
        $servers->queue_push($db, $item, FALSE);
        $item_unpause = new action (COMMAND_CONTINUE, "$command $args", $item->get_username(), TRUE);
        $offset = $item->get_preview() ? DB_LOCK_TIMEOUT_PREVIEW : DB_LOCK_TIMEOUT_DEFAULT;
//       echo_debug("Scheduling '$command $args' again at $offset + " . time(), DEBUG_SERVER);
//        echo_debug_var($item, DEBUG_SERVER);
        $job = new job($item_unpause, time() + $offset, NULL); //try again in XX secs
        $servers->add_schedule($db, $job);
    } catch (exception $e) {
        echo_debug_trace($e, DEBUG_SERVER);
        throw $e;
    }
}


function schedule_locked_item(DatabaseConnection $db, server_data &$servers, action $item)
{
    echo_debug('Dl still locked, pausing', DEBUG_SERVER);
    $id = $item->get_id();
    $command = $item->get_command();
    $args = $item->get_args();
    $item->pause($db, TRUE, 'root');
    $item_unpause = new action (COMMAND_CONTINUE, "$command $args", $item->get_username(), TRUE);
    $offset = $item->get_preview() ? DB_LOCK_TIMEOUT_PREVIEW : DB_LOCK_TIMEOUT_DEFAULT;
    $job = new job($item_unpause, time() + $offset, NULL); //try again in 30 secs
    $servers->add_schedule($db, $job);
}


function urdd_kill($pid, $signal)
{
    $r = posix_kill($pid, $signal);
    if ($r === FALSE) {
        $ec = posix_get_last_error();
        $msg = '';
        if ($ec != 0)
            $msg = posix_strerror($ec);
        throw new exception('Kill Failed: ' . $msg);
    }
}


?>
